package com.example.selfservicestation.mob

import android.content.Context
import androidx.annotation.WorkerThread
import com.epton.sdk.SerialPort
import com.example.selfservicestation.constant.DEFAULT_CARD_BAUD
import com.example.selfservicestation.constant.DEFAULT_CARD_DOOR_BAUD
import com.example.selfservicestation.constant.DEFAULT_CARD_DOOR_PORT
import com.example.selfservicestation.constant.DEFAULT_CARD_PORT
import com.example.selfservicestation.constant.DEFAULT_LOCK_BAUD
import com.example.selfservicestation.constant.DEFAULT_LOCK_PORT
import com.example.selfservicestation.constant.SP_CARD_BAUD
import com.example.selfservicestation.constant.SP_CARD_DOOR_BAUD
import com.example.selfservicestation.constant.SP_CARD_DOOR_PORT
import com.example.selfservicestation.constant.SP_CARD_PORT
import com.example.selfservicestation.constant.SP_LOCK_BAUD
import com.example.selfservicestation.constant.SP_LOCK_PORT
import com.example.selfservicestation.singleton.SharedPreferenceUtil
import com.example.selfservicestation.util.Executor
import com.example.selfservicestation.util.Logger
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.*

/**
 * 串口通信管理器
 */
class PortManager private constructor(
    private val input: InputStream,
    private val output: OutputStream,
    val index: Int
) {

    // 是否正在监听
    @Volatile
    private var listening = false

    /**
     * 向串口发送数据
     */
    fun send(data: ByteArray) : Boolean {
        try {
            output.write(data)
            output.flush()
            return true
        } catch (e: IOException) {
            Logger.e("PortManager", "串口写数据失败", e)
            return false
        }
    }

    var t : Thread ? = null

    /**
     * 监听串口数据
     */
    fun listen(listener: (ByteArray) -> Unit) {
        if (listening) {
            throw IllegalStateException("已经被监听")
        }
        listening = true
        t = Thread {
            val buffer = ByteArray(BUFFER_SIZE)
            while (listening) {
                try {
                    val data = ByteArray(input.read(buffer))
                    System.arraycopy(buffer, 0, data, 0, data.size)
                    if (data.isNotEmpty()) {
                        listener(data)
                    }
                } catch (e: Exception) {
                    Logger.e("PortManager", "串口读取或处理异常", e)
                }
            }
        }
        t?.isDaemon = true
        t?.start()
    }

    /**
     * 关闭
     */
    fun close() {
        t = null
        listening = false
        try {
            input.close()
            output.close()
        } catch (e: Exception) { }
    }

    companion object {

        private const val BUFFER_SIZE = 256

        /**
         * 打开串口
         * @param port 串口号，从 0 开始
         * @param bps 波特率，正整数
         */
        @WorkerThread
        fun open(port: Int, bps: Int, usb: Boolean) : PortManager? {
            var blocked = true
            val thread = Thread.currentThread()
            Executor.delayOnMain({
                // 如果线程被阻塞达到 1 秒，则打断唤醒
                if (blocked) {
                    Logger.w("PortManager", "超 0.5 秒未打开串口，打断唤醒")
                    thread.interrupt()
                }
            }, 500)
            try {
                val file = File(if(usb) "/dev/ttyUSB${port}" else "/dev/ttyS${port}")
                Logger.i("PortManager", "连接 port file")
                SerialPort(file, bps, 0).run {
                    blocked = false
                    Logger.i("PortManager", "建立 SerialPort")
                    return PortManager(inputStream, outputStream,port)
                }
            } catch (e: Exception) {
                blocked = false
                Logger.e("PortManager", "异常", e)
                Logger.e("PortManager","串口[${port}, ${bps}, ${usb}]打开失败[${e.javaClass.simpleName}]${e.message}")

                return null
            }
        }

        /**
         * 打开主控板
         */
        @WorkerThread
        fun openCtrlBord(ctx: Context) : PortManager? {
            val port = SharedPreferenceUtil.getInt(SP_LOCK_PORT, DEFAULT_LOCK_PORT)
            val bps = SharedPreferenceUtil.getInt(SP_LOCK_BAUD, DEFAULT_LOCK_BAUD)
            val usb = false
            Logger.i("PortManager", "主控板 port = ${port}, bps = ${bps}, usb = ${usb}")
            return open(port, bps, usb)
        }

        /**
         * 打开扫码头1
         */
        @WorkerThread
        fun openScanner1(ctx: Context) : PortManager? {
            val port = SharedPreferenceUtil.getInt(SP_CARD_DOOR_PORT, DEFAULT_CARD_DOOR_PORT)
            val bps = SharedPreferenceUtil.getInt(SP_CARD_DOOR_BAUD, DEFAULT_CARD_DOOR_BAUD)
            val usb = false
            Logger.i("PortManager", "扫码头1 port = ${port}, bps = ${bps}, usb = ${usb}")
            return open(port, bps, usb)
        }

        /**
         * 打开扫码头2
         */
        @WorkerThread
        fun openScanner2(ctx: Context) : PortManager? {
            val port = SharedPreferenceUtil.getInt(SP_CARD_PORT, DEFAULT_CARD_PORT)
            val bps = SharedPreferenceUtil.getInt(SP_CARD_BAUD, DEFAULT_CARD_BAUD)
            val usb = false
            Logger.i("PortManager", "扫码头2 port = ${port}, bps = ${bps}, usb = ${usb}")
            return open(port, bps, usb)
        }

    }

}
